﻿using Microsoft.Extensions.Configuration;
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
using S7.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VOL.Core.Configuration;

namespace VOL.Core.Utilities
{
    //plc中类型与c#类型 bool => Bit
    //Byte => byte
    //word => ushort
    //DWord => uint
    //Int => short
    //DInt => int
    //Real => float
    //LReal => double
    //String => string
    //DateTimeLong=>datetime
    //s7wstring=>string
    //ReadTimeout,WriteTimeout,分别为读取和写入等待时间
    /// <summary>
    /// plc帮助类
    /// </summary>
    public class PlcHelper
    {


        public Plc Plc;
        private static string ip { get; set; }
        public PlcHelper()
        {
            IConfigurationSection section = AppSetting.GetSection("PLC");
            ip = section["Ip"];
        }
        //// 私有静态实例变量
        private static PlcHelper instance = null;

        //// 私有构造函数，确保外部无法直接实例化


        //// 公有静态属性，用于获取单例实例
        public static PlcHelper Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new PlcHelper();
                }
                return instance;
            }
        }
        /// <summary>
        /// 连接plc   
        /// </summary>
        /// <param name="cpuType">cpu型号</param>
        /// <param name="ip">plc的ip地址</param>
        /// <param name="rack">机架号</param>
        /// <param name="slot">插槽号</param>
        /// <param name="ipNew">新的ip地址</param>
        /// <returns>是否成功</returns>
        /// 默认值填充  在1500中机架号，插槽号通常为0和1。可根据实际情况赋值
        public bool OpenPlc(CpuType cpuType = CpuType.S71500, short rack = 0, short slot = 1,string ipNew="")
        {

            Plc = new Plc(cpuType, (ipNew!=""? ipNew:ip), rack, slot);
            Plc.Open();
            if (Plc.IsConnected) return true;
            else return false;
        }
        /// <summary>
        /// 关闭plc连接
        /// </summary>
        /// <param name="plc">引用的plc实例</param>
        public void ClosePlc(Plc plc)
        {
            if (plc != null)
            {  Plc.Close(); }
           
        }

        /// <summary>
        /// 读取bool类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public bool ReadBool(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock,byte bitAdr = 0)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.Bit, 1,bitAdr);
            return (bool)result;
        }
        /// <summary>
        /// 写入bool类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteBool(int dbBlock, int startByteAdr, bool Value, DataType dataType = DataType.DataBlock, int bitAdr=-1)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value, bitAdr);
        }

        /// <summary>
        /// 读取int类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public short ReadInt(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.Int, 1);
            return (short)result;
        }
        /// <summary>
        /// 写入int类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteInt(int dbBlock, int startByteAdr, short Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取Dint类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public int ReadDInt(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.Int, 1);
            return (int)result;
        }
        /// <summary>
        /// 写入Dint类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteDInt(int dbBlock, int startByteAdr, int Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取char类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public char ReadChar(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.String, 1);
            return (char)result;
        }
        /// <summary>
        /// 写入char类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteChar(int dbBlock, int startByteAdr, char Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取byte类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public byte ReadByte(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock, byte bitAdr = 0)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.Byte, 1,bitAdr);
            return (byte)result;
        }
        /// <summary>
        /// 写入byte类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        //public void WriteByte(int dbBlock, int startByteAdr, byte Value, DataType dataType = DataType.DataBlock, int bitAdr = 0)
        //{
        //    Plc.Write(dataType, dbBlock, startByteAdr, Value,bitAdr);

        //}
        ///// <summary>
        ///// 写入byte类型
        ///// </summary>
        ///// <param name="dbBlock">所选择的数据库块</param>
        ///// <param name="startByteAdr">数据偏移量</param>
        ///// <param name="Value">写入值</param>
        ///// <param name="dataType">数据块类型</param>
        ///// <returns></returns>
        public void WriteByte(int dbBlock, int startByteAdr, byte Value, DataType dataType = DataType.DataBlock)
        {
          //  Plc.Write(DataType.DataBlock, dbInt, strAdr, Convert.ToByte(Data));
            Plc.Write(dataType, dbBlock, startByteAdr,Convert.ToByte( Value));
        }

        /// <summary>
        /// 读取word类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public ushort ReadWord(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.Int, 1);
            UInt16 myUInt16 = (UInt16)Math.Abs((short)result);
            return (ushort)myUInt16;
        }
        /// <summary>
        /// 写入word类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteWord(int dbBlock, int startByteAdr, ushort Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取Dword类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public uint ReadDWord(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.DWord, 1);
            return (uint)result;
        }
        /// <summary>
        /// 写入Dword类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteDWord(int dbBlock, int startByteAdr, uint Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取real类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public float ReadReal(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.Real, 1);
            return (float)result;
        }
        /// <summary>
        /// 写入real类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteReal(int dbBlock, int startByteAdr, float Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取Lreal类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public double ReadLReal(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.Int, 1);
            return (double)result;
        }
        /// <summary>
        /// 写入Lreal类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteLReal(int dbBlock, int startByteAdr, double Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取dateandtime类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public DateTime ReadDateAndTime(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.DateTime, 1);
            return (DateTime)result;
        }
        /// <summary>
        /// 写入dateandtime类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteDateAndTime(int dbBlock, int startByteAdr, DateTime Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }
        /// <summary>
        /// 读取任意值类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="type">数组类型</param>
        /// <param name="count">读取值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public dynamic Read(int dbBlock, int startByteAdr, VarType type, int count, DataType dataType = DataType.DataBlock)
        {
            switch (type)
            {
                case VarType.String:
                    byte[] stringDemo = Plc.ReadBytes(DataType.DataBlock, dbBlock, startByteAdr + 2, (byte)Plc.Read(DataType.DataBlock, dbBlock, startByteAdr + 1, VarType.Byte, 1));//+2表示读取偏移值（跳过）的字符
                    return Encoding.Default.GetString(stringDemo);
                case VarType.Bit:
                    return (bool)Plc.Read(dataType, dbBlock, startByteAdr, VarType.Bit, count);
                case VarType.Int:
                    return (short)Plc.Read(dataType, dbBlock, startByteAdr, VarType.Int, count);
                case VarType.DInt:
                    return (int)Plc.Read(dataType, dbBlock, startByteAdr, VarType.DInt, count);
                case VarType.S7WString:
                    return Plc.Read(dataType, dbBlock, startByteAdr, VarType.S7WString, count = 254).ToString();//254为wstring默认存储字符数
                case VarType.Byte:
                    return (byte)Plc.Read(dataType, dbBlock, startByteAdr, VarType.Byte, count);
                case VarType.Word:
                    return (ushort)Plc.Read(dataType, dbBlock, startByteAdr, VarType.Word, count);
                case VarType.DWord:
                    return (uint)Plc.Read(dataType, dbBlock, startByteAdr, VarType.DWord, count);
                case VarType.Real:
                    return (float)Plc.Read(dataType, dbBlock, startByteAdr, VarType.Real, count);
                case VarType.LReal:
                    return (double)Plc.Read(dataType, dbBlock, startByteAdr, VarType.LReal, count);
                case VarType.DateTimeLong:
                    return (DateTime)Plc.Read(dataType, dbBlock, startByteAdr, VarType.DateTimeLong, count);
                default:
                    throw new Exception("数据类型不存在");
            }
        }

        /// <summary>
        /// 写入任意值类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="type">原数据类型</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void Write(int dbBlock, int startByteAdr, VarType type, object Value, DataType dataType = DataType.DataBlock)
        {
            switch (type)
            {
                case VarType.String:
                    Plc.Write(DataType.DataBlock, dbBlock, startByteAdr + 1, (byte)Value.ToString().Length);//长度需要改成byte类型
                    Plc.Write(DataType.DataBlock, dbBlock, startByteAdr + 2, Value);
                    break;
                case VarType.Bit:
                    Plc.Write(dataType, dbBlock, startByteAdr, bool.Parse(Value.ToString()));
                    break;
                case VarType.Int:
                    Plc.Write(dataType, dbBlock, startByteAdr, short.Parse(Value.ToString()));
                    break;
                case VarType.DInt:
                    Plc.Write(dataType, dbBlock, startByteAdr, int.Parse(Value.ToString()));
                    break;
                case VarType.Byte:
                    Plc.Write(dataType, dbBlock, startByteAdr, byte.Parse(Value.ToString()));
                    break;
                case VarType.Word:
                    Plc.Write(dataType, dbBlock, startByteAdr, ushort.Parse(Value.ToString()));
                    break;
                case VarType.DWord:
                    Plc.Write(dataType, dbBlock, startByteAdr, uint.Parse(Value.ToString()));
                    break;
                case VarType.Real:
                    Plc.Write(dataType, dbBlock, startByteAdr, float.Parse(Value.ToString()));
                    break;
                case VarType.LReal:
                    Plc.Write(dataType, dbBlock, startByteAdr, double.Parse(Value.ToString()));
                    break;
                case VarType.DateTimeLong:
                    Plc.Write(dataType, dbBlock, startByteAdr, DateTime.Parse(Value.ToString()));
                    break;
                default:
                    throw new Exception("数据类型不存在");
            }
        }

        /// <summary>
        /// 读取array[]类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="type">数组类型</param>
        /// <param name="count">读取长度</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public dynamic ReadArray(int dbBlock, int startByteAdr, VarType type, int count, DataType dataType = DataType.DataBlock)
        {
            switch (type)
            {
                case VarType.Bit:
                    return (bool[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.Bit, count);
                case VarType.Int:
                    return (short[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.Int, count);
                case VarType.DInt:
                    return (int[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.DInt, count);
                case VarType.Byte:
                    return (byte[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.Byte, count);
                case VarType.Word:
                    return (ushort[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.Word, count);
                case VarType.DWord:
                    return (uint[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.DWord, count);
                case VarType.Real:
                    return (float[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.Real, count);
                case VarType.LReal:
                    return (double[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.LReal, count);
                case VarType.DateTimeLong:
                    return (DateTime[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.DateTimeLong, count);
                default:
                    throw new Exception("数据类型不存在");
            }
        }

        /// <summary>
        /// 写入array[]类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteArray(int dbBlock, int startByteAdr, object Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取string类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public string ReadString(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var count = Plc.Read(DataType.DataBlock, dbBlock, startByteAdr + 1, VarType.Byte, 1);//+1表示读取偏移值的长度
            byte[] stringDemo = Plc.ReadBytes(DataType.DataBlock, dbBlock, startByteAdr + 2, (byte)count);//+2表示读取偏移值（跳过）的字符
            return Encoding.Default.GetString(stringDemo);
        }
        /// <summary>
        /// 写入string类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteString(int dbBlock, int startByteAdr, string Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(DataType.DataBlock, dbBlock, startByteAdr + 1, (byte)Value.Length);//长度需要改成byte类型
            Plc.Write(DataType.DataBlock, dbBlock, startByteAdr + 2, Value);
        }
        /// <summary>
        /// 读取wstring类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public string ReadWString(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(DataType.DataBlock, dbBlock, startByteAdr, VarType.S7WString, 254);
            return result.ToString();
        }

        /// <summary>  以下两种方式不推荐，会重复开启tcp连接占用资源
        /// 标签方式读取
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <returns></returns>
        public dynamic ReadTags(string dbBlock)
        {
            //例：Plc.Read("DB2.DBX0.0"); 其中db2表示数据库名称，0.0表示偏移量  dbx表示数据块
            return Plc.Read(dbBlock);
        }

        /// <summary>
        /// 标签方式写入
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="vaule">写入值</param>
        /// <returns></returns>
        public void WriteTags(string dbBlock, object vaule)
        {
            //例：Plc.Read("DB2.DBX0.0",true); 其中db2表示数据库名称，0.0表示偏移量,true表示将其转换为true
            Plc.Write(dbBlock, vaule);
        }
        /// <summary>
        /// 获取西门子PLC字符串数组--WString
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public byte[] GetPLCWStringByteArray(string str)
        {
            byte[] value = Encoding.BigEndianUnicode.GetBytes(str);
            byte[] head = BitConverter.GetBytes((short)254);
            byte[] length = BitConverter.GetBytes((short)str.Length);
            Array.Reverse(head);
            Array.Reverse(length);
            head = head.Concat(length).ToArray();
            value = head.Concat(value).ToArray();
            return value;
        }
    }


    //190
    public class PlcHelper190
    {


        public Plc Plc;
        private static string ip { get; set; }
        public PlcHelper190()
        {
            IConfigurationSection section = AppSetting.GetSection("PLC");
            ip = section["Ip190"];
        }
        //// 私有静态实例变量
        private static PlcHelper190 instance = null;

        //// 私有构造函数，确保外部无法直接实例化


        //// 公有静态属性，用于获取单例实例
        public static PlcHelper190 Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new PlcHelper190();
                }
                return instance;
            }
        }
        /// <summary>
        /// 连接plc   
        /// </summary>
        /// <param name="cpuType">cpu型号</param>
        /// <param name="ip">plc的ip地址</param>
        /// <param name="rack">机架号</param>
        /// <param name="slot">插槽号</param>
        /// <param name="ipNew">新的ip地址</param>
        /// <returns>是否成功</returns>
        /// 默认值填充  在1500中机架号，插槽号通常为0和1。可根据实际情况赋值
        public bool OpenPlc(CpuType cpuType = CpuType.S71500, short rack = 0, short slot = 1, string ipNew = "")
        {

            Plc = new Plc(cpuType, (ipNew != "" ? ipNew : ip), rack, slot);
            Plc.Open();
            if (Plc.IsConnected) return true;
            else return false;
        }
        /// <summary>
        /// 关闭plc连接
        /// </summary>
        /// <param name="plc">引用的plc实例</param>
        public void ClosePlc(Plc plc)
        {
            if (plc != null)
            { Plc.Close(); }

        }

        /// <summary>
        /// 读取bool类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public bool ReadBool(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock, byte bitAdr = 0)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.Bit, 1, bitAdr);
            return (bool)result;
        }
        /// <summary>
        /// 写入bool类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteBool(int dbBlock, int startByteAdr, bool Value, DataType dataType = DataType.DataBlock, int bitAdr = -1)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value, bitAdr);
        }

        /// <summary>
        /// 读取int类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public short ReadInt(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.Int, 1);
            return (short)result;
        }
        /// <summary>
        /// 写入int类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteInt(int dbBlock, int startByteAdr, short Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取Dint类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public int ReadDInt(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.Int, 1);
            return (int)result;
        }
        /// <summary>
        /// 写入Dint类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteDInt(int dbBlock, int startByteAdr, int Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取char类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public char ReadChar(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.String, 1);
            return (char)result;
        }
        /// <summary>
        /// 写入char类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteChar(int dbBlock, int startByteAdr, char Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取byte类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public byte ReadByte(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock, byte bitAdr = 0)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.Byte, 1, bitAdr);
            return (byte)result;
        }
        /// <summary>
        /// 写入byte类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        //public void WriteByte(int dbBlock, int startByteAdr, byte Value, DataType dataType = DataType.DataBlock, int bitAdr = 0)
        //{
        //    Plc.Write(dataType, dbBlock, startByteAdr, Value,bitAdr);

        //}
        ///// <summary>
        ///// 写入byte类型
        ///// </summary>
        ///// <param name="dbBlock">所选择的数据库块</param>
        ///// <param name="startByteAdr">数据偏移量</param>
        ///// <param name="Value">写入值</param>
        ///// <param name="dataType">数据块类型</param>
        ///// <returns></returns>
        public void WriteByte(int dbBlock, int startByteAdr, byte Value, DataType dataType = DataType.DataBlock)
        {
            //  Plc.Write(DataType.DataBlock, dbInt, strAdr, Convert.ToByte(Data));
            Plc.Write(dataType, dbBlock, startByteAdr, Convert.ToByte(Value));
        }

        /// <summary>
        /// 读取word类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public ushort ReadWord(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.Int, 1);
            UInt16 myUInt16 = (UInt16)Math.Abs((short)result);
            return (ushort)myUInt16;
        }
        /// <summary>
        /// 写入word类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteWord(int dbBlock, int startByteAdr, ushort Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取Dword类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public uint ReadDWord(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.DWord, 1);
            return (uint)result;
        }
        /// <summary>
        /// 写入Dword类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteDWord(int dbBlock, int startByteAdr, uint Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取real类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public float ReadReal(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.Real, 1);
            return (float)result;
        }
        /// <summary>
        /// 写入real类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteReal(int dbBlock, int startByteAdr, float Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取Lreal类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public double ReadLReal(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.Int, 1);
            return (double)result;
        }
        /// <summary>
        /// 写入Lreal类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteLReal(int dbBlock, int startByteAdr, double Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取dateandtime类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public DateTime ReadDateAndTime(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(dataType, dbBlock, startByteAdr, VarType.DateTime, 1);
            return (DateTime)result;
        }
        /// <summary>
        /// 写入dateandtime类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteDateAndTime(int dbBlock, int startByteAdr, DateTime Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }
        /// <summary>
        /// 读取任意值类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="type">数组类型</param>
        /// <param name="count">读取值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public dynamic Read(int dbBlock, int startByteAdr, VarType type, int count, DataType dataType = DataType.DataBlock)
        {
            switch (type)
            {
                case VarType.String:
                    byte[] stringDemo = Plc.ReadBytes(DataType.DataBlock, dbBlock, startByteAdr + 2, (byte)Plc.Read(DataType.DataBlock, dbBlock, startByteAdr + 1, VarType.Byte, 1));//+2表示读取偏移值（跳过）的字符
                    return Encoding.Default.GetString(stringDemo);
                case VarType.Bit:
                    return (bool)Plc.Read(dataType, dbBlock, startByteAdr, VarType.Bit, count);
                case VarType.Int:
                    return (short)Plc.Read(dataType, dbBlock, startByteAdr, VarType.Int, count);
                case VarType.DInt:
                    return (int)Plc.Read(dataType, dbBlock, startByteAdr, VarType.DInt, count);
                case VarType.S7WString:
                    return Plc.Read(dataType, dbBlock, startByteAdr, VarType.S7WString, count = 254).ToString();//254为wstring默认存储字符数
                case VarType.Byte:
                    return (byte)Plc.Read(dataType, dbBlock, startByteAdr, VarType.Byte, count);
                case VarType.Word:
                    return (ushort)Plc.Read(dataType, dbBlock, startByteAdr, VarType.Word, count);
                case VarType.DWord:
                    return (uint)Plc.Read(dataType, dbBlock, startByteAdr, VarType.DWord, count);
                case VarType.Real:
                    return (float)Plc.Read(dataType, dbBlock, startByteAdr, VarType.Real, count);
                case VarType.LReal:
                    return (double)Plc.Read(dataType, dbBlock, startByteAdr, VarType.LReal, count);
                case VarType.DateTimeLong:
                    return (DateTime)Plc.Read(dataType, dbBlock, startByteAdr, VarType.DateTimeLong, count);
                default:
                    throw new Exception("数据类型不存在");
            }
        }

        /// <summary>
        /// 写入任意值类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="type">原数据类型</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void Write(int dbBlock, int startByteAdr, VarType type, object Value, DataType dataType = DataType.DataBlock)
        {
            switch (type)
            {
                case VarType.String:
                    Plc.Write(DataType.DataBlock, dbBlock, startByteAdr + 1, (byte)Value.ToString().Length);//长度需要改成byte类型
                    Plc.Write(DataType.DataBlock, dbBlock, startByteAdr + 2, Value);
                    break;
                case VarType.Bit:
                    Plc.Write(dataType, dbBlock, startByteAdr, bool.Parse(Value.ToString()));
                    break;
                case VarType.Int:
                    Plc.Write(dataType, dbBlock, startByteAdr, short.Parse(Value.ToString()));
                    break;
                case VarType.DInt:
                    Plc.Write(dataType, dbBlock, startByteAdr, int.Parse(Value.ToString()));
                    break;
                case VarType.Byte:
                    Plc.Write(dataType, dbBlock, startByteAdr, byte.Parse(Value.ToString()));
                    break;
                case VarType.Word:
                    Plc.Write(dataType, dbBlock, startByteAdr, ushort.Parse(Value.ToString()));
                    break;
                case VarType.DWord:
                    Plc.Write(dataType, dbBlock, startByteAdr, uint.Parse(Value.ToString()));
                    break;
                case VarType.Real:
                    Plc.Write(dataType, dbBlock, startByteAdr, float.Parse(Value.ToString()));
                    break;
                case VarType.LReal:
                    Plc.Write(dataType, dbBlock, startByteAdr, double.Parse(Value.ToString()));
                    break;
                case VarType.DateTimeLong:
                    Plc.Write(dataType, dbBlock, startByteAdr, DateTime.Parse(Value.ToString()));
                    break;
                default:
                    throw new Exception("数据类型不存在");
            }
        }

        /// <summary>
        /// 读取array[]类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="type">数组类型</param>
        /// <param name="count">读取长度</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public dynamic ReadArray(int dbBlock, int startByteAdr, VarType type, int count, DataType dataType = DataType.DataBlock)
        {
            switch (type)
            {
                case VarType.Bit:
                    return (bool[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.Bit, count);
                case VarType.Int:
                    return (short[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.Int, count);
                case VarType.DInt:
                    return (int[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.DInt, count);
                case VarType.Byte:
                    return (byte[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.Byte, count);
                case VarType.Word:
                    return (ushort[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.Word, count);
                case VarType.DWord:
                    return (uint[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.DWord, count);
                case VarType.Real:
                    return (float[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.Real, count);
                case VarType.LReal:
                    return (double[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.LReal, count);
                case VarType.DateTimeLong:
                    return (DateTime[])Plc.Read(dataType, dbBlock, startByteAdr, VarType.DateTimeLong, count);
                default:
                    throw new Exception("数据类型不存在");
            }
        }

        /// <summary>
        /// 写入array[]类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteArray(int dbBlock, int startByteAdr, object Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(dataType, dbBlock, startByteAdr, Value);
        }

        /// <summary>
        /// 读取string类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public string ReadString(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var count = Plc.Read(DataType.DataBlock, dbBlock, startByteAdr + 1, VarType.Byte, 1);//+1表示读取偏移值的长度
            byte[] stringDemo = Plc.ReadBytes(DataType.DataBlock, dbBlock, startByteAdr + 2, (byte)count);//+2表示读取偏移值（跳过）的字符
            return Encoding.Default.GetString(stringDemo);
        }
        /// <summary>
        /// 写入string类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="Value">写入值</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public void WriteString(int dbBlock, int startByteAdr, string Value, DataType dataType = DataType.DataBlock)
        {
            Plc.Write(DataType.DataBlock, dbBlock, startByteAdr + 1, (byte)Value.Length);//长度需要改成byte类型
            Plc.Write(DataType.DataBlock, dbBlock, startByteAdr + 2, Value);
        }
        /// <summary>
        /// 读取wstring类型
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="startByteAdr">数据偏移量</param>
        /// <param name="dataType">数据块类型</param>
        /// <returns></returns>
        public string ReadWString(int dbBlock, int startByteAdr, DataType dataType = DataType.DataBlock)
        {
            var result = Plc.Read(DataType.DataBlock, dbBlock, startByteAdr, VarType.S7WString, 254);
            return result.ToString();
        }

        /// <summary>  以下两种方式不推荐，会重复开启tcp连接占用资源
        /// 标签方式读取
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <returns></returns>
        public dynamic ReadTags(string dbBlock)
        {
            //例：Plc.Read("DB2.DBX0.0"); 其中db2表示数据库名称，0.0表示偏移量  dbx表示数据块
            return Plc.Read(dbBlock);
        }

        /// <summary>
        /// 标签方式写入
        /// </summary>
        /// <param name="dbBlock">所选择的数据库块</param>
        /// <param name="vaule">写入值</param>
        /// <returns></returns>
        public void WriteTags(string dbBlock, object vaule)
        {
            //例：Plc.Read("DB2.DBX0.0",true); 其中db2表示数据库名称，0.0表示偏移量,true表示将其转换为true
            Plc.Write(dbBlock, vaule);
        }
        /// <summary>
        /// 获取西门子PLC字符串数组--WString
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public byte[] GetPLCWStringByteArray(string str)
        {
            byte[] value = Encoding.BigEndianUnicode.GetBytes(str);
            byte[] head = BitConverter.GetBytes((short)254);
            byte[] length = BitConverter.GetBytes((short)str.Length);
            Array.Reverse(head);
            Array.Reverse(length);
            head = head.Concat(length).ToArray();
            value = head.Concat(value).ToArray();
            return value;
        }
    }
}
